// 文件系统结构定义
// 参考 xv6-riscv 实现

#ifndef __FS_H__
#define __FS_H__

#include "types.h"
#include "param.h"

#define ROOTINO  1   // root i-number
#define BSIZE 1024   // block size

// 磁盘布局:
// [ boot block | super block | log | inode blocks |
//                                          free bit map | data blocks]
//
// mkfs 计算超级块并构建初始文件系统
struct superblock {
  uint magic;        // 必须是 FSMAGIC
  uint size;         // 文件系统镜像大小（块数）
  uint nblocks;      // 数据块数量
  uint ninodes;      // inode数量
  uint nlog;         // 日志块数量
  uint logstart;     // 第一个日志块的块号
  uint inodestart;   // 第一个inode块的块号
  uint bmapstart;    // 第一个空闲位图块的块号
};

#define FSMAGIC 0x10203040

#define NDIRECT 12
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT)

// 磁盘上的inode结构
struct dinode {
  short type;           // 文件类型
  short major;          // 主设备号（仅T_DEVICE类型）
  short minor;          // 次设备号（仅T_DEVICE类型）
  short nlink;          // 文件系统中的链接数
  uint size;            // 文件大小（字节）
  uint addrs[NDIRECT+1]; // 数据块地址
};

// 每个块的inode数
#define IPB           (BSIZE / sizeof(struct dinode))

// 包含inode i的块
#define IBLOCK(i, sb)     ((i) / IPB + sb.inodestart)

// 每个块的位图位数
#define BPB           (BSIZE*8)

// 包含块b的位图的块
#define BBLOCK(b, sb) ((b)/BPB + sb.bmapstart)

// 目录是包含dirent结构序列的文件
#define DIRSIZ 14

// name字段可能有DIRSIZ个字符，不以NUL结尾
struct dirent {
  ushort inum;
  char name[DIRSIZ];
};

// 日志头结构（存储在日志的第一个块）
struct logheader {
  int n;                // 日志中的块数
  int block[LOGSIZE];   // 每个块在文件系统中的位置
};

#endif // __FS_H__